using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace FARAgent
{
    public partial class FARForm : Form
    {
        // Execute Action
        private static string m_InputExtension = @".mapping";
        private static string m_OutputExtension = @".rtxt";
        private static List<string> m_ListOfCriterias;
        private static List<string> m_ListOfFiles;

        // make the m_Regex and m_Match class level variables
        // to make happen find next
        private Regex m_Regex;
        private Match m_Match;

        private string SourceFileName;
        private string MappingFileName;

        private List<string> ListOfCriteriasName = new List<string>();
        private Dictionary<string, string> ListOfCriterias = new Dictionary<string, string>();

        private List<string> ListOfFileName = new List<string>();
        private Dictionary<string, string> ListOfFiles = new Dictionary<string, string>();

        private Boolean IsMatchWholeWord;
        private Boolean IsUseWildcards;
        private Boolean IsIgnoreCase;
        private Boolean IsCultureInvariant;
        private Boolean IsMultiLine;
        private Boolean IsSingleLine;
        private Boolean IsIndentedInput;
        private Boolean IsUseRegulatExpression;

        // variable to indicate finding first time 
        // or is it a find next
        private bool IsFirstFind = true;

        public FARForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// This function makes and returns a RegEx object
        /// depending on user input
        /// </summary>
        /// <returns></returns>
        private Regex GetRegExpression(string search)
        {
            Regex _Result;
            String _Search;
            RegexOptions _RegexOptions = new RegexOptions();

            // Get what the user entered
            _Search = search;

            if (this.IsUseRegulatExpression)
            {
                // If regular expressions checkbox is selected,
                // our job is easy. Just do nothing
            }
            // wild cards checkbox checked
            else if (this.IsUseWildcards)
            {
                _Search = _Search.Replace("*", @"\w*");     // multiple characters wildcard (*)
                _Search = _Search.Replace("?", @"\w");      // single character wildcard (?)

                // if wild cards selected, find whole words only
                _Search = String.Format("{0}{1}{0}", @"\b", _Search);
            }
            else
            {
                // replace escape characters
                _Search = Regex.Escape(_Search);
            }

            // Is whole word check box checked?
            if (IsMatchWholeWord)
            {
                _Search = String.Format("{0}{1}{0}", @"\b", _Search);
            }

            // Regex Options
            if (IsIgnoreCase) _RegexOptions = RegexOptions.IgnoreCase;
            if (IsCultureInvariant) _RegexOptions |= RegexOptions.CultureInvariant;
            if (IsMultiLine) _RegexOptions |= RegexOptions.Multiline;
            if (IsSingleLine) _RegexOptions |= RegexOptions.Singleline;
            if (IsIndentedInput) _RegexOptions |= RegexOptions.IgnorePatternWhitespace;

            if (IsIgnoreCase || IsCultureInvariant || IsMultiLine || IsSingleLine || IsIndentedInput)
            {
                _Result = new Regex(_Search, _RegexOptions);
            }
            else
            {
                _Result = new Regex(_Search);
            }

            return _Result;
        }

        /// <summary>
        /// finds the text in searchTextBox in contentTextBox
        /// </summary>
        private void FindText()
        {
            // Is this the first time find is called?
            // Then make instances of RegEx and Match
            if (IsFirstFind)
            {
                m_Regex = GetRegExpression(searchTextBox.Text);
                m_Match = m_Regex.Match(richContentTextBox.Text);
                IsFirstFind = false;
            }
            else
            {
                // m_Match.NextMatch() is also ok, except in Replace
                // In replace as text is changing, it is necessary to
                // find again
                //m_Match = m_Match.NextMatch();
                m_Match = m_Regex.Match(richContentTextBox.Text, m_Match.Index + 1);
            }

            // found a m_Match?
            if (m_Match.Success)
            {
                // then select it
                richContentTextBox.SelectionStart = m_Match.Index;
                richContentTextBox.SelectionLength = m_Match.Length;

                richContentTextBox.Focus();
            }
            else // didn't find? bad luck.
            {
                MessageBox.Show(String.Format("Cannot find '{0}'.   ", searchTextBox.Text),
                        Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                IsFirstFind = true;
            }
        }

        #region Regex Options

        /// <summary>
        /// TextChanged event handler of searchTextBox
        /// Set IsFirstFind to true, if text changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void searchTextBox_TextChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
        }

        /// <summary>
        /// CheckedChanged event handler of matchWholeWordCheckBox
        /// Set IsFirstFind to true, if check box is checked or unchecked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void matchWholeWordCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsMatchWholeWord = ((CheckBox)sender).Checked;
        }

        /// <summary>
        /// CheckedChanged event handler of useWildcardsCheckBox
        /// Set IsFirstFind to true, if check box is checked or unchecked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void useWildcardsCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsUseWildcards = ((CheckBox)sender).Checked;
        }

        /// <summary>
        /// CheckedChanged event handler of matchCaseCheckBox
        /// Set IsFirstFind to true, if check box is checked or unchecked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ignoreCaseCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsIgnoreCase = ((CheckBox)sender).Checked;
        }

        private void cultureInvariantCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsCultureInvariant = ((CheckBox)sender).Checked;
        }

        private void multiLineCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsMultiLine = ((CheckBox)sender).Checked;

        }

        private void singleLineCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsSingleLine = ((CheckBox)sender).Checked;
        }

        private void indentedInputCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            IsFirstFind = true;
            IsIndentedInput = ((CheckBox)sender).Checked;
        }

        private void useRegulatExpressionCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            chkUseWildcards.Checked = false;
            chkUseWildcards.Enabled = !((CheckBox)sender).Checked;

            IsUseRegulatExpression = ((CheckBox)sender).Checked;
        }

        #endregion

        /// <summary>
        /// Click event handler of find button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFind_Click(object sender, EventArgs e)
        {
            if (SourceFileName == null || SourceFileName == "") return;
            FindText();
        }

        /// <summary>
        /// Click event handler of replaceButton
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnReplace_Click(object sender, EventArgs e)
        {
            if (SourceFileName == null || SourceFileName == "") return;

            // Make a local RegEx and Match instances
            Regex regexTemp = GetRegExpression(searchTextBox.Text);
            Match matchTemp = regexTemp.Match(richContentTextBox.SelectedText);

            if (matchTemp.Success)
            {
                // check if it is an exact m_Match
                if (matchTemp.Value == richContentTextBox.SelectedText)
                {
                    richContentTextBox.SelectedText = replaceTextBox.Text;
                }
            }
            
            FindText();
        }

        /// <summary>
        /// Click event handler of replaceAllButton
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnReplaceAll_Click(object sender, EventArgs e)
        {
            if (SourceFileName == null || SourceFileName == "") return;

            Regex replaceRegex = GetRegExpression(searchTextBox.Text);
            String replacedString;

            // get the current SelectionStart
            int selectedPos = richContentTextBox.SelectionStart;

            // get the replaced string
            replacedString = replaceRegex.Replace(richContentTextBox.Text, replaceTextBox.Text);

            // Is the text changed?
            if (richContentTextBox.Text != replacedString)
            {
                // then replace it
                richContentTextBox.Text = replacedString;
                MessageBox.Show("Replacements are made.   ", Application.ProductName,
                    MessageBoxButtons.OK, MessageBoxIcon.Information);

                // restore the SelectionStart
                richContentTextBox.SelectionStart = selectedPos;
            }
            else // inform user if no replacements are made
            {
                MessageBox.Show(String.Format("Cannot find '{0}'.   ", searchTextBox.Text),
                    Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            richContentTextBox.Focus();
        }

        private void FARForm_Load(object sender, EventArgs e)
        {
            IsMatchWholeWord = chkMatchWholeWord.Checked;
            IsUseWildcards = chkUseWildcards.Checked;
            IsIgnoreCase = chkIgnoreCase.Checked;
            IsCultureInvariant = chkCultureInvariant.Checked;
            IsMultiLine = chkMultiLine.Checked;
            IsSingleLine = chkSingleLine.Checked;
            IsIndentedInput = chkIndentedInput.Checked;
            IsUseRegulatExpression = chkUseRegulatExpression.Checked;

            IsFirstFind = true;
        }

        private void btnOpenFile_Click(object sender, EventArgs e)
        {
            lstOfFiles.DataSource = null;

            OpenFolder();

            lstOfFiles.DataSource = ListOfFileName;


            //lstOfCriterias.DataSource = null;
            //OpenFile();
            //LoadCriterias();
            //lstOfCriterias.DataSource = ListOfCriteriasName;
        }

        private void OpenFolder()
        {
            folderDlg.ShowDialog();
            if (folderDlg.SelectedPath != "" || folderDlg.SelectedPath != null)
            {
                SourceFileName = folderDlg.SelectedPath;
                txtFileName.Text = folderDlg.SelectedPath;

                ListOfFiles = new Dictionary<string, string>();
                ListOfFileName = new List<string>();
                foreach (string _File in Directory.GetFiles(folderDlg.SelectedPath))
                {
                    FileInfo _FileInfo = new FileInfo(_File);

                    // "Text Files|*.txt|Csv Files|*.csv|Result Files|*.rtxt|All Files|*.*"
                    if (_FileInfo.Extension.ToLower().Contains(".txt") ||
                        _FileInfo.Extension.ToLower().Contains(".csv") ||
                        _FileInfo.Extension.ToLower().Contains(".html"))
                    {
                        ListOfFiles.Add(_FileInfo.Name, _File);
                        ListOfFileName.Add(_FileInfo.Name);
                    }
                }
            }
        }

        private void SaveCriterias()
        {
            if (MappingFileName == null || MappingFileName == "")
            {
                // Add MessageBox
                return;
            }

            // create a writer and open the file
            using (TextWriter tw = new StreamWriter(MappingFileName))
            {

                foreach (KeyValuePair<string, string> pairKeyValue in ListOfCriterias)
                {
                    tw.WriteLine(pairKeyValue.Key + ";" + pairKeyValue.Value);
                }
            }     
        }

        private void LoadCriterias()
        {
            ListOfCriteriasName = new List<string>();
            ListOfCriterias = new Dictionary<string, string>();

            if (!File.Exists(MappingFileName))
            {
                SaveCriterias();
            }


            using (StreamReader r = new StreamReader(MappingFileName))
            {
                string line;
                while ((line = r.ReadLine()) != null)
                {
                    string[] dic = line.Split(';');
                    string m_Key = string.Empty;
                    string m_Value = string.Empty;

                    for (int i = 0; i <= dic.Length-1; i++)
                    {
                        if (i <= 0)
                        {
                            m_Key += dic[i] + ";";
                        } 
                        else
                        {
                            m_Value += dic[i] + ";";
                        }
                    }

                    ListOfCriterias.Add(m_Key.Substring(0,m_Key.Length-1), m_Value.Substring(0,m_Value.Length-1));
                    ListOfCriteriasName.Add(m_Key.Substring(0, m_Key.Length - 1));
                }
            }

        }

        private void OpenFile()
        { 
            
            oFileDlg.Title = "Open File";
            oFileDlg.DefaultExt = "txt";
            oFileDlg.Filter = "Text Files|*.txt|Csv Files|*.csv|Result Files|*.rtxt|All Files|*.*";
            oFileDlg.ShowDialog();
                
            if (oFileDlg.FileName != null || oFileDlg.FileName != "")
            {
                SourceFileName = oFileDlg.FileName;
                MappingFileName = oFileDlg.FileName + m_InputExtension;
                txtFileName.Text = oFileDlg.FileName;

                string m_FileExtension = System.IO.Path.GetExtension(oFileDlg.FileName).ToUpper();

                if (m_FileExtension == ".RTF")
                {
                    richContentTextBox.LoadFile(oFileDlg.FileName, RichTextBoxStreamType.RichText);
                }
                else
                {
                    richContentTextBox.LoadFile(oFileDlg.FileName, RichTextBoxStreamType.PlainText);
                }
            }
        }

        private void ShowFile(string FileName)
        {

            string _File = ListOfFiles[FileName];

            MappingFileName = _File + m_InputExtension;

            string m_FileExtension = System.IO.Path.GetExtension(_File).ToUpper();

            if (m_FileExtension == ".RTF")
            {
                richContentTextBox.LoadFile(_File, RichTextBoxStreamType.RichText);
            }
            else
            {
                richContentTextBox.LoadFile(_File, RichTextBoxStreamType.PlainText);
            }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {

            //IsMatchWholeWord;
            //IsIgnoreCase;
            //IsUseWildcards;
            //IsUseRegulatExpression;

            string _ItemKey = string.Empty;
            string _ItemValue = string.Empty;

            if (!searchTextBox.Text.Equals(""))
            {
                //_ItemKey += searchTextBox.Text + ";";
                //_ItemValue += replaceTextBox.Text + ";";
                _ItemKey += searchTextBox.Text.Trim() + ";";
                _ItemValue += replaceTextBox.Text.Trim() + ";";

                // Regex Options
                _ItemValue += IsMatchWholeWord.ToString() + ";";
                _ItemValue += IsUseWildcards.ToString() + ";";
                _ItemValue += IsIgnoreCase.ToString() + ";";
                _ItemValue += IsCultureInvariant.ToString() + ";";
                _ItemValue += IsMultiLine.ToString() + ";";
                _ItemValue += IsSingleLine.ToString() + ";";
                _ItemValue += IsIndentedInput.ToString() + ";";
                _ItemValue += IsUseRegulatExpression.ToString() + ";";

                if (!ListOfCriterias.ContainsKey(_ItemKey.Substring(0,_ItemKey.Length-1)))
                {
                    ListOfCriterias.Add(_ItemKey.Substring(0, _ItemKey.Length - 1), _ItemValue.Substring(0, _ItemValue.Length - 1));
                    ListOfCriteriasName.Add(_ItemKey.Substring(0,_ItemKey.Length-1));

                    lstOfCriterias.DataSource = null;
                    lstOfCriterias.DataSource = ListOfCriteriasName;

                    lstOfCriterias.SelectedIndex = lstOfCriterias.SelectedIndex + 1;
                }
                else 
                {
                    ListOfCriterias[_ItemKey.Substring(0, _ItemKey.Length - 1)] = _ItemValue.Substring(0, _ItemValue.Length - 1);
                }
            }

            // Save Mapping File
            SaveCriterias();
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            // The Remove button was clicked.
            int selectedIndex = lstOfCriterias.SelectedIndex;
            if (selectedIndex != -1)
            {
                try
                {
                    // Remove the item in the List.
                    ListOfCriterias.Remove(lstOfCriterias.Text);
                    ListOfCriteriasName.RemoveAt(selectedIndex);

                }
                catch
                {
                }

                lstOfCriterias.DataSource = null;
                lstOfCriterias.DataSource = ListOfCriteriasName;
            }

            // Save Mapping File
            SaveCriterias();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveCriterias();
        }

        private void lstOfCriterias_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!lstOfCriterias.Text.Equals(""))
            {

                searchTextBox.Text = lstOfCriterias.Text;

                string[] _criteria = ListOfCriterias[lstOfCriterias.Text].Split(';');

                replaceTextBox.Text = _criteria[0].ToString();

                this.IsMatchWholeWord = System.Convert.ToBoolean(_criteria[1]);
                this.IsUseWildcards = System.Convert.ToBoolean(_criteria[2]);
                this.IsIgnoreCase = System.Convert.ToBoolean(_criteria[3]);
                this.IsCultureInvariant = System.Convert.ToBoolean(_criteria[4]);
                this.IsMultiLine = System.Convert.ToBoolean(_criteria[5]);
                this.IsSingleLine = System.Convert.ToBoolean(_criteria[6]);
                this.IsIndentedInput = System.Convert.ToBoolean(_criteria[7]);
                this.IsUseRegulatExpression = System.Convert.ToBoolean(_criteria[8]);

                chkMatchWholeWord.Checked = IsMatchWholeWord;
                chkUseWildcards.Checked = IsUseWildcards;
                chkIgnoreCase.Checked = IsIgnoreCase;
                chkCultureInvariant.Checked = IsCultureInvariant;
                chkMultiLine.Checked = IsMultiLine;
                chkSingleLine.Checked = IsSingleLine;
                chkIndentedInput.Checked = IsIndentedInput;
                chkUseRegulatExpression.Checked = IsUseRegulatExpression;

            }
        }

        private void lstOfFiles_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!lstOfFiles.Text.Equals(""))
            {
                lstOfCriterias.DataSource = null;

                ShowFile(lstOfFiles.Text);

                LoadCriterias();

                lstOfCriterias.DataSource = ListOfCriteriasName;
            }
        }

        private void btnExecute_Click(object sender, EventArgs e)
        {
            FAREngine m_FAREngine;

            if (Directory.Exists(SourceFileName))
            {
                m_ListOfFiles = new List<string>();
                foreach (string m_FileName in Directory.GetFiles(SourceFileName))
                {
                    FileInfo _FileInfo = new FileInfo(m_FileName);
                    if (_FileInfo.Extension.ToLower().Equals(m_InputExtension)) 
                    {

                        System.Console.WriteLine(m_FileName);

                        // Read Criteria File
                        m_ListOfCriterias = new List<string>();
                        using (StreamReader r = new StreamReader(m_FileName))
                        {
                            string line;
                            while ((line = r.ReadLine()) != null)
                            {
                                m_ListOfCriterias.Add(line);
                            }
                        }

                        // Create the destiny File
                        using (TextWriter tw = new StreamWriter(m_FileName.Replace(m_InputExtension, m_OutputExtension)))
                        {
                            // Open the source File
                            using (StreamReader r = new StreamReader(m_FileName.Replace(m_InputExtension, "")))
                            {
                                string line;
                                while ((line = r.ReadLine()) != null)
                                {
                                    if (!line.Equals(""))
                                    {
                                        string _Content = line;
                                        foreach (string criteria in m_ListOfCriterias)
                                        {
                                            m_FAREngine = new FAREngine(criteria);

                                            _Content = m_FAREngine.ReplaceInContent(_Content);

                                            //if (_Content != line)
                                            //{
                                            //    break;
                                            //}
                                        }

                                        tw.WriteLine(_Content);

                                    }
                                    else
                                        tw.WriteLine(line);
                                }
                            }
                        }
                    }
                }

                //foreach (string m_FileName in m_ListOfFiles)
                //{
                //}
            }
        }
    }
}